home *** CD-ROM | disk | FTP | other *** search
/ Amiga Games Extra 1996 September / Amiga Games Extra CD-ROM 9-1996.iso / userbox / publicdomain / vim-4.2 / src / memfile.c < prev    next >
C/C++ Source or Header  |  1996-06-09  |  28KB  |  1,183 lines

  1. /* vi:set ts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved        by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  */
  8.  
  9. /* for debugging */
  10. #define CHECK(c, s)    if (c) printf(s)
  11.  
  12. /*
  13.  * memfile.c: Contains the functions for handling blocks of memory which can
  14.  * be stored in a file. This is the implementation of a sort of virtual memory.
  15.  *
  16.  * A memfile consists of a sequence of blocks. The blocks numbered from 0
  17.  * upwards have been assigned a place in the actual file. The block number
  18.  * is equal to the page number in the file. The
  19.  * blocks with negative numbers are currently in memory only. They can be
  20.  * assigned a place in the file when too much memory is being used. At that
  21.  * moment they get a new, positive, number. A list is used for translation of
  22.  * negative to positive numbers.
  23.  *
  24.  * The size of a block is a multiple of a page size, normally the page size of
  25.  * the device the file is on. Most blocks are 1 page long. A Block of multiple
  26.  * pages is used for a line that does not fit in a single page.
  27.  *
  28.  * Each block can be in memory and/or in a file. The block stays in memory
  29.  * as long as it is locked. If it is no longer locked it can be swapped out to
  30.  * the file. It is only written to the file if it has been changed.
  31.  *
  32.  * Under normal operation the file is created when opening the memory file and
  33.  * deleted when closing the memory file. Only with recovery an existing memory
  34.  * file is opened.
  35.  */
  36.  
  37. #if defined MSDOS  ||  defined WIN32
  38. # include <io.h>        /* for lseek(), must be before vim.h */
  39. #endif
  40.  
  41. #include "vim.h"
  42. #include "globals.h"
  43. #include "proto.h"
  44. #include "option.h"
  45. #ifdef HAVE_FCNTL_H
  46. # include <fcntl.h>
  47. #endif
  48.  
  49. /* 
  50.  * Some systems have the page size in statfs, some in stat
  51.  */
  52. #ifdef HAVE_SYS_STATFS_H
  53. # include <sys/statfs.h>
  54. # define STATFS statfs
  55. # define F_BSIZE f_bsize
  56. # ifdef MINT
  57. #  define fstatfs(fd, buf, len, nul) fstat((fd), (buf))
  58. # endif
  59. #else
  60. # define STATFS stat
  61. # define F_BSIZE st_blksize
  62. # define fstatfs(fd, buf, len, nul) fstat((fd), (buf))
  63. #endif
  64.  
  65. /*
  66.  * for Amiga Dos 2.0x we use Flush
  67.  */
  68. #ifdef AMIGA
  69. # ifndef NO_ARP
  70. extern int dos2;                        /* this is in amiga.c */
  71. # endif
  72. # ifdef SASC
  73. #  include <proto/dos.h>
  74. #  include <ios1.h>                        /* for chkufb() */
  75. # endif
  76. #endif
  77.  
  78. #define MEMFILE_PAGE_SIZE 4096            /* default page size */
  79.  
  80. static long total_mem_used = 0;            /* total memory used for memfiles */
  81.  
  82. static void mf_ins_hash __ARGS((MEMFILE *, BHDR *));
  83. static void mf_rem_hash __ARGS((MEMFILE *, BHDR *));
  84. static BHDR *mf_find_hash __ARGS((MEMFILE *, blocknr_t));
  85. static void mf_ins_used __ARGS((MEMFILE *, BHDR *));
  86. static void mf_rem_used __ARGS((MEMFILE *, BHDR *));
  87. static BHDR *mf_release __ARGS((MEMFILE *, int));
  88. static BHDR *mf_alloc_bhdr __ARGS((MEMFILE *, int));
  89. static void mf_free_bhdr __ARGS((BHDR *));
  90. static void mf_ins_free __ARGS((MEMFILE *, BHDR *));
  91. static BHDR *mf_rem_free __ARGS((MEMFILE *));
  92. static int    mf_read __ARGS((MEMFILE *, BHDR *));
  93. static int    mf_write __ARGS((MEMFILE *, BHDR *));
  94. static int    mf_trans_add __ARGS((MEMFILE *, BHDR *));
  95. static void mf_do_open __ARGS((MEMFILE *, char_u *, int));
  96.  
  97. /*
  98.  * The functions for using a memfile:
  99.  *
  100.  * mf_open()        open a new or existing memfile
  101.  * mf_open_file()    open a swap file for an existing memfile
  102.  * mf_close()        close (and delete) a memfile
  103.  * mf_new()            create a new block in a memfile and lock it
  104.  * mf_get()            get an existing block and lock it
  105.  * mf_put()            unlock a block, may be marked for writing
  106.  * mf_free()        remove a block
  107.  * mf_sync()        sync changed parts of memfile to disk
  108.  * mf_release_all()    release as much memory as possible
  109.  * mf_trans_del()    may translate negative to positive block number
  110.  * mf_fullname()    make file name full path (use before first :cd)
  111.  */
  112.  
  113. /*
  114.  * mf_open: open an existing or new memory block file
  115.  *
  116.  *    fname:        name of file to use (NULL means no file at all)
  117.  *                Note: fname must have been allocated, it is not copied!
  118.  *                        If opening the file fails, fname is NOT freed.
  119.  *  trunc_file:        if TRUE: file should be truncated when opening
  120.  *
  121.  *  If fname != NULL and file cannot be opened, fail.
  122.  *
  123.  * return value: identifier for this memory block file.
  124.  */
  125.     MEMFILE *
  126. mf_open(fname, trunc_file)
  127.     char_u    *fname;
  128.     int        trunc_file;
  129. {
  130.     MEMFILE            *mfp;
  131.     int                i;
  132.     long            size;
  133. #ifdef UNIX
  134.     struct STATFS     stf;
  135. #endif
  136.  
  137.     if ((mfp = (MEMFILE *)alloc((unsigned)sizeof(MEMFILE))) == NULL)
  138.         return NULL;
  139.  
  140.     if (fname == NULL)        /* no file for this memfile, use memory only */
  141.     {
  142.         mfp->mf_fname = NULL;
  143.         mfp->mf_xfname = NULL;
  144.         mfp->mf_fd = -1;
  145.     }
  146.     else
  147.     {
  148.         mf_do_open(mfp, fname, trunc_file);        /* try to open the file */
  149.  
  150.         /* if the file cannot be opened, return here */
  151.         if (mfp->mf_fd < 0)
  152.         {
  153.             vim_free(mfp);
  154.             return NULL;
  155.         }
  156.     }
  157.  
  158.     mfp->mf_free_first = NULL;            /* free list is empty */
  159.     mfp->mf_used_first = NULL;            /* used list is empty */
  160.     mfp->mf_used_last = NULL;
  161.     mfp->mf_dirty = FALSE;
  162.     mfp->mf_used_count = 0;
  163.     for (i = 0; i < MEMHASHSIZE; ++i)
  164.     {
  165.         mfp->mf_hash[i] = NULL;            /* hash lists are empty */
  166.         mfp->mf_trans[i] = NULL;        /* trans lists are empty */
  167.     }
  168.     mfp->mf_page_size = MEMFILE_PAGE_SIZE;
  169.  
  170. #ifdef UNIX
  171.     /*
  172.      * Try to set the page size equal to the block size of the device.
  173.      * Speeds up I/O a lot.
  174.      * NOTE: minimal block size depends on size of block 0 data! It's not done
  175.      * with a sizeof(), because block 0 is defined in memline.c (Sorry).
  176.      * The maximal block size is arbitrary.
  177.      */
  178.     if (mfp->mf_fd >= 0 &&
  179.                     fstatfs(mfp->mf_fd, &stf, sizeof(struct statfs), 0) == 0 &&
  180.                     stf.F_BSIZE >= 1048 && stf.F_BSIZE <= 50000)
  181.         mfp->mf_page_size = stf.F_BSIZE;
  182. #endif
  183.  
  184.     if (mfp->mf_fd < 0 || trunc_file ||
  185.                                 (size = lseek(mfp->mf_fd, 0L, SEEK_END)) <= 0)
  186.         mfp->mf_blocknr_max = 0;        /* no file or empty file */
  187.     else
  188.         mfp->mf_blocknr_max = size / mfp->mf_page_size;
  189.     mfp->mf_blocknr_min = -1;
  190.     mfp->mf_neg_count = 0;
  191.     mfp->mf_infile_count = mfp->mf_blocknr_max;
  192.     if (mfp->mf_fd < 0)
  193.         mfp->mf_used_count_max = 0;            /* no limit */
  194.     else
  195.         mfp->mf_used_count_max = p_mm * 1024 / mfp->mf_page_size;
  196.  
  197.     return mfp;
  198. }
  199.  
  200. /*
  201.  * mf_open_file: open a file for an existing memfile. Used when updatecount
  202.  *                 set from 0 to some value.
  203.  *
  204.  *    fname:        name of file to use (NULL means no file at all)
  205.  *                Note: fname must have been allocated, it is not copied!
  206.  *                        If opening the file fails, fname is NOT freed.
  207.  *
  208.  * return value: FAIL if file could not be opened, OK otherwise
  209.  */
  210.     int
  211. mf_open_file(mfp, fname)
  212.     MEMFILE        *mfp;
  213.     char_u        *fname;
  214. {
  215.     mf_do_open(mfp, fname, TRUE);                /* try to open the file */
  216.  
  217.     if (mfp->mf_fd < 0)
  218.         return FAIL;
  219.  
  220.     mfp->mf_dirty = TRUE;
  221.     return OK;
  222. }
  223.  
  224. /*
  225.  * close a memory file and delete the associated file if 'del_file' is TRUE
  226.  */
  227.     void
  228. mf_close(mfp, del_file)
  229.     MEMFILE    *mfp;
  230.     int        del_file;
  231. {
  232.     BHDR        *hp, *nextp;
  233.     NR_TRANS    *tp, *tpnext;
  234.     int            i;
  235.  
  236.     if (mfp == NULL)                /* safety check */
  237.         return;
  238.     if (mfp->mf_fd >= 0)
  239.     {
  240.         if (close(mfp->mf_fd) < 0)
  241.             EMSG("Close error on swap file");
  242.     }
  243.     if (del_file && mfp->mf_fname != NULL)
  244.         vim_remove(mfp->mf_fname);
  245.                                             /* free entries in used list */
  246.     for (hp = mfp->mf_used_first; hp != NULL; hp = nextp)
  247.     {
  248.         total_mem_used -= hp->bh_page_count * mfp->mf_page_size;
  249.         nextp = hp->bh_next;
  250.         mf_free_bhdr(hp);
  251.     }
  252.     while (mfp->mf_free_first != NULL)        /* free entries in free list */
  253.         vim_free(mf_rem_free(mfp));
  254.     for (i = 0; i < MEMHASHSIZE; ++i)        /* free entries in trans lists */
  255.         for (tp = mfp->mf_trans[i]; tp != NULL; tp = tpnext)
  256.         {
  257.             tpnext = tp->nt_next;
  258.             vim_free(tp);
  259.         }
  260.     vim_free(mfp->mf_fname);
  261.     vim_free(mfp->mf_xfname);
  262.     vim_free(mfp);
  263. }
  264.  
  265. /*
  266.  * get a new block
  267.  *
  268.  *   negative: TRUE if negative block number desired (data block)
  269.  */
  270.     BHDR *
  271. mf_new(mfp, negative, page_count)
  272.     MEMFILE        *mfp;
  273.     int            negative;
  274.     int            page_count;
  275. {
  276.     BHDR    *hp;            /* new BHDR */
  277.     BHDR    *freep;            /* first block in free list */
  278.     char_u    *p;
  279.  
  280.     /*
  281.      * If we reached the maximum size for the used memory blocks, release one
  282.      * If a BHDR is returned, use it and adjust the page_count if necessary.
  283.      */
  284.     hp = mf_release(mfp, page_count);
  285.  
  286. /*
  287.  * Decide on the number to use:
  288.  * If there is a free block, use its number.
  289.  * Otherwise use mf_block_min for a negative number, mf_block_max for
  290.  * a positive number.
  291.  */
  292.     freep = mfp->mf_free_first;
  293.     if (!negative && freep != NULL && freep->bh_page_count >= page_count)
  294.     {
  295.         /*
  296.          * If the block in the free list has more pages, take only the number
  297.          * of pages needed and allocate a new BHDR with data
  298.          *
  299.          * If the number of pages matches and mf_release did not return a BHDR,
  300.          * use the BHDR from the free list and allocate the data
  301.          *
  302.          * If the number of pages matches and mf_release returned a BHDR,
  303.          * just use the number and free the BHDR from the free list
  304.          */
  305.         if (freep->bh_page_count > page_count)
  306.         {
  307.             if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
  308.                 return NULL;
  309.             hp->bh_bnum = freep->bh_bnum;
  310.             freep->bh_bnum += page_count;
  311.             freep->bh_page_count -= page_count;
  312.         }
  313.         else if (hp == NULL)        /* need to allocate memory for this block */
  314.         {
  315.             if ((p = (char_u *)alloc(mfp->mf_page_size * page_count)) == NULL)
  316.                 return NULL;
  317.             hp = mf_rem_free(mfp);
  318.             hp->bh_data = p;
  319.         }
  320.         else                /* use the number, remove entry from free list */
  321.         {
  322.             freep = mf_rem_free(mfp);
  323.             hp->bh_bnum = freep->bh_bnum;
  324.             vim_free(freep);
  325.         }
  326.     }
  327.     else        /* get a new number */
  328.     {
  329.         if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
  330.             return NULL;
  331.         if (negative)
  332.         {
  333.             hp->bh_bnum = mfp->mf_blocknr_min--;
  334.             mfp->mf_neg_count++;
  335.         }
  336.         else
  337.         {
  338.             hp->bh_bnum = mfp->mf_blocknr_max;
  339.             mfp->mf_blocknr_max += page_count;
  340.         }
  341.     }
  342.     hp->bh_flags = BH_LOCKED | BH_DIRTY;        /* new block is always dirty */
  343.     mfp->mf_dirty = TRUE;
  344.     hp->bh_page_count = page_count;
  345.     mf_ins_used(mfp, hp);
  346.     mf_ins_hash(mfp, hp);
  347.  
  348.     return hp;
  349. }
  350.  
  351. /*
  352.  * get existing block 'nr' with 'page_count' pages
  353.  *
  354.  * Note: The caller should first check a negative nr with mf_trans_del()
  355.  */
  356.     BHDR *
  357. mf_get(mfp, nr, page_count)
  358.     MEMFILE        *mfp;
  359.     blocknr_t    nr;
  360.     int            page_count;
  361. {
  362.     BHDR    *hp;
  363.                                                 /* doesn't exist */
  364.     if (nr >= mfp->mf_blocknr_max || nr <= mfp->mf_blocknr_min)
  365.         return NULL;
  366.  
  367.     /*
  368.      * see if it is in the cache
  369.      */
  370.     hp = mf_find_hash(mfp, nr);
  371.     if (hp == NULL)        /* not in the hash list */
  372.     {
  373.         if (nr < 0 || nr >= mfp->mf_infile_count)    /* can't be in the file */
  374.             return NULL;
  375.  
  376.         /* could check here if the block is in the free list */
  377.  
  378.         /*
  379.          * Check if we need to flush an existing block.
  380.          * If so, use that block.
  381.          * If not, allocate a new block.
  382.          */
  383.         hp = mf_release(mfp, page_count);
  384.         if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
  385.             return NULL;
  386.  
  387.         hp->bh_bnum = nr;
  388.         hp->bh_flags = 0;
  389.         hp->bh_page_count = page_count;
  390.         if (mf_read(mfp, hp) == FAIL)        /* cannot read the block! */
  391.         {
  392.             mf_free_bhdr(hp);
  393.             return NULL;
  394.         }
  395.     }
  396.     else
  397.     {
  398.         mf_rem_used(mfp, hp);    /* remove from list, insert in front below */
  399.         mf_rem_hash(mfp, hp);
  400.     }
  401.  
  402.     hp->bh_flags |= BH_LOCKED;
  403.     mf_ins_used(mfp, hp);        /* put in front of used list */
  404.     mf_ins_hash(mfp, hp);        /* put in front of hash list */
  405.  
  406.     return hp;
  407. }
  408.  
  409. /*
  410.  * release the block *hp
  411.  *
  412.  *   dirty: Block must be written to file later
  413.  *     infile: Block should be in file (needed for recovery)
  414.  *
  415.  *  no return value, function cannot fail
  416.  */
  417.     void
  418. mf_put(mfp, hp, dirty, infile)
  419.     MEMFILE    *mfp;
  420.     BHDR    *hp;
  421.     int        dirty;
  422.     int        infile;
  423. {
  424.     int        flags;
  425.  
  426.     flags = hp->bh_flags;
  427.     CHECK((flags & BH_LOCKED) == 0, "block was not locked");
  428.     flags &= ~BH_LOCKED;
  429.     if (dirty)
  430.     {
  431.         flags |= BH_DIRTY;
  432.         mfp->mf_dirty = TRUE;
  433.     }
  434.     hp->bh_flags = flags;
  435.     if (infile)
  436.         mf_trans_add(mfp, hp);        /* may translate negative in positive nr */
  437. }
  438.  
  439. /*
  440.  * block *hp is no longer in used, may put it in the free list of memfile *mfp
  441.  */
  442.     void
  443. mf_free(mfp, hp)
  444.     MEMFILE    *mfp;
  445.     BHDR    *hp;
  446. {
  447.     vim_free(hp->bh_data);        /* free the memory */
  448.     mf_rem_hash(mfp, hp);        /* get *hp out of the hash list */
  449.     mf_rem_used(mfp, hp);        /* get *hp out of the used list */
  450.     if (hp->bh_bnum < 0)
  451.     {
  452.         vim_free(hp);            /* don't want negative numbers in free list */
  453.         mfp->mf_neg_count--;
  454.     }
  455.     else
  456.         mf_ins_free(mfp, hp);    /* put *hp in the free list */
  457. }
  458.  
  459. /*
  460.  * sync the memory file *mfp to disk
  461.  *    if 'all' is FALSE blocks with negative numbers are not synced, even when
  462.  *  they are dirty!
  463.  *  if 'check_char' is TRUE, stop syncing when a character becomes available,
  464.  *  but sync at least one block.
  465.  *  if 'do_fsync' is TRUE make sure buffers are flushed to disk, so they will
  466.  *  survive a system crash.
  467.  *
  468.  * Return FAIL for failure, OK otherwise
  469.  */
  470.     int
  471. mf_sync(mfp, all, check_char, do_fsync)
  472.     MEMFILE    *mfp;
  473.     int        all;
  474.     int        check_char;
  475.     int        do_fsync;
  476. {
  477.     int        status;
  478.     BHDR    *hp;
  479. #ifdef SYNC_DUP_CLOSE
  480.     int        fd;
  481. #endif
  482.  
  483.     if (mfp->mf_fd < 0)        /* there is no file, nothing to do */
  484.     {
  485.         mfp->mf_dirty = FALSE;
  486.         return FAIL;
  487.     }
  488.  
  489.     /*
  490.      * sync from last to first (may reduce the probability of an inconsistent
  491.      * file) If a write fails, it is very likely caused by a full filesystem.
  492.      * Then we only try to write blocks within the existing file. If that also
  493.      * fails then we give up.
  494.      */
  495.     status = OK;
  496.     for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
  497.         if ((all || hp->bh_bnum >= 0) && (hp->bh_flags & BH_DIRTY) &&
  498.                     (status == OK || (hp->bh_bnum >= 0 &&
  499.                         hp->bh_bnum < mfp->mf_infile_count)))
  500.         {
  501.             if (mf_write(mfp, hp) == FAIL)
  502.             {
  503.                 if (status == FAIL)        /* double error: quit syncing */
  504.                     break;
  505.                 status = FAIL;
  506.             }
  507.             if (check_char && mch_char_avail())    /* char available now */
  508.                 break;
  509.         }
  510.     
  511.     /*
  512.      * If the whole list is flushed, the memfile is not dirty anymore.
  513.      * In case of an error this flag is also set, to avoid trying all the time.
  514.      */
  515.     if (hp == NULL || status == FAIL)
  516.         mfp->mf_dirty = FALSE;
  517.  
  518.     if (do_fsync && *p_sws != NUL)
  519.     {
  520. #if defined(UNIX)
  521. # ifdef HAVE_FSYNC
  522.         /*
  523.          * most Unixes have the very useful fsync() function, just what we need.
  524.          * However, with OS/2 and EMX it is also available, but there are
  525.          * reports of bad problems with it (a bug in HPFS.IFS).
  526.          * So we disable use of it here in case someone tries to be smart
  527.          * and changes conf_os2.h... (even though there is no __EMX__ test
  528.          * in the #if, as __EMX__ does not have sync(); we hope for a timely
  529.          * sync from the system itself).
  530.          */
  531. #  if defined(__EMX__)
  532.    error "Dont use fsync with EMX! Read emxdoc.doc or emxfix01.doc for info."
  533. #  endif
  534.         if (STRCMP(p_sws, "fsync") == 0)
  535.         {
  536.             if (fsync(mfp->mf_fd))
  537.                 status = FAIL;
  538.         }
  539.         else
  540. # endif
  541.              sync();
  542. #endif
  543. #ifdef DJGPP
  544.         if (_dos_commit(mfp->mf_fd))
  545.             status = FAIL;
  546. #else
  547. # ifdef SYNC_DUP_CLOSE
  548.         /*
  549.          * MSdos is a bit more work: Duplicate the file handle and close it.
  550.          * This should flush the file to disk.
  551.          */
  552.         if ((fd = dup(mfp->mf_fd)) >= 0)
  553.             close(fd);
  554. # endif
  555. #endif
  556. #ifdef AMIGA
  557.         /*
  558.          * Flush() only exists for AmigaDos 2.0.
  559.          * For 1.3 it should be done with close() + open(), but then the risk
  560.          * is that the open() may fail and lose the file....
  561.          */
  562. # ifndef NO_ARP
  563.         if (dos2)
  564. # endif
  565. # ifdef SASC
  566.         {
  567.             struct UFB *fp = chkufb(mfp->mf_fd);
  568.  
  569.             if (fp != NULL)
  570.                 Flush(fp->ufbfh);
  571.         }
  572. # else
  573. #  ifdef _DCC
  574.         {
  575.             BPTR fh = (BPTR)fdtofh(mfp->mf_fd);
  576.  
  577.             if (fh != 0)
  578.                 Flush(fh);
  579.             }
  580. #  else /* assume Manx */
  581.             Flush(_devtab[mfp->mf_fd].fd);
  582. #  endif
  583. # endif
  584. #endif /* AMIGA */
  585.     }
  586.  
  587.     return status;
  588. }
  589.  
  590. /*
  591.  * insert block *hp in front of hashlist of memfile *mfp
  592.  */
  593.     static void
  594. mf_ins_hash(mfp, hp)
  595.     MEMFILE    *mfp;
  596.     BHDR    *hp;
  597. {
  598.     BHDR    *hhp;
  599.     int        hash;
  600.  
  601.     hash = MEMHASH(hp->bh_bnum);
  602.     hhp = mfp->mf_hash[hash];
  603.     hp->bh_hash_next = hhp;
  604.     hp->bh_hash_prev = NULL;
  605.     if (hhp != NULL)
  606.         hhp->bh_hash_prev = hp;
  607.     mfp->mf_hash[hash] = hp;
  608. }
  609.  
  610. /*
  611.  * remove block *hp from hashlist of memfile list *mfp
  612.  */
  613.     static void
  614. mf_rem_hash(mfp, hp)
  615.     MEMFILE    *mfp;
  616.     BHDR    *hp;
  617. {
  618.     if (hp->bh_hash_prev == NULL)
  619.         mfp->mf_hash[MEMHASH(hp->bh_bnum)] = hp->bh_hash_next;
  620.     else
  621.         hp->bh_hash_prev->bh_hash_next = hp->bh_hash_next;
  622.     
  623.     if (hp->bh_hash_next)
  624.         hp->bh_hash_next->bh_hash_prev = hp->bh_hash_prev;
  625. }
  626.  
  627. /*
  628.  * look in hash lists of memfile *mfp for block header with number 'nr'
  629.  */
  630.     static BHDR *
  631. mf_find_hash(mfp, nr)
  632.     MEMFILE        *mfp;
  633.     blocknr_t    nr;
  634. {
  635.     BHDR        *hp;
  636.  
  637.     for (hp = mfp->mf_hash[MEMHASH(nr)]; hp != NULL; hp = hp->bh_hash_next)
  638.         if (hp->bh_bnum == nr)
  639.             break;
  640.     return hp;
  641. }
  642.  
  643. /*
  644.  * insert block *hp in front of used list of memfile *mfp
  645.  */
  646.     static void
  647. mf_ins_used(mfp, hp)
  648.     MEMFILE    *mfp;
  649.     BHDR    *hp;
  650. {
  651.     hp->bh_next = mfp->mf_used_first;
  652.     mfp->mf_used_first = hp;
  653.     hp->bh_prev = NULL;
  654.     if (hp->bh_next == NULL)        /* list was empty, adjust last pointer */
  655.         mfp->mf_used_last = hp;
  656.     else
  657.         hp->bh_next->bh_prev = hp;
  658.     mfp->mf_used_count += hp->bh_page_count;
  659.     total_mem_used += hp->bh_page_count * mfp->mf_page_size;
  660. }
  661.  
  662. /*
  663.  * remove block *hp from used list of memfile *mfp
  664.  */
  665.     static void
  666. mf_rem_used(mfp, hp)
  667.     MEMFILE    *mfp;
  668.     BHDR    *hp;
  669. {
  670.     if (hp->bh_next == NULL)        /* last block in used list */
  671.         mfp->mf_used_last = hp->bh_prev;
  672.     else
  673.         hp->bh_next->bh_prev = hp->bh_prev;
  674.     if (hp->bh_prev == NULL)        /* first block in used list */
  675.         mfp->mf_used_first = hp->bh_next;
  676.     else
  677.         hp->bh_prev->bh_next = hp->bh_next;
  678.     mfp->mf_used_count -= hp->bh_page_count;
  679.     total_mem_used -= hp->bh_page_count * mfp->mf_page_size;
  680. }
  681.  
  682. /*
  683.  * Release the least recently used block from the used list if the number
  684.  * of used memory blocks gets to big.
  685.  *
  686.  * Return the block header to the caller, including the memory block, so
  687.  * it can be re-used. Make sure the page_count is right.
  688.  */
  689.     static BHDR *
  690. mf_release(mfp, page_count)
  691.     MEMFILE        *mfp;
  692.     int            page_count;
  693. {
  694.     BHDR        *hp;
  695.  
  696.         /*
  697.          * don't release a block if
  698.          *        there is no file for this memfile
  699.          * or
  700.          *         there is no limit to the number of blocks for this memfile or
  701.          *        the maximum is not reached yet
  702.          *    and
  703.          *        total memory used is not up to 'maxmemtot'
  704.          */
  705.     if (mfp->mf_fd < 0 || ((mfp->mf_used_count < mfp->mf_used_count_max ||
  706.                         mfp->mf_used_count_max == 0) &&
  707.                         (total_mem_used >> 10) < p_mmt))
  708.         return NULL;
  709.  
  710.     for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
  711.         if (!(hp->bh_flags & BH_LOCKED))
  712.             break;
  713.     if (hp == NULL)        /* not a single one that can be released */
  714.         return NULL;
  715.  
  716.         /*
  717.          * If the block is dirty, write it.
  718.          * If the write fails we don't free it.
  719.          */
  720.     if ((hp->bh_flags & BH_DIRTY) && mf_write(mfp, hp) == FAIL)
  721.         return NULL;
  722.  
  723.     mf_rem_used(mfp, hp);
  724.     mf_rem_hash(mfp, hp);
  725.  
  726. /*
  727.  * If a BHDR is returned, make sure that the page_count of bh_data is right
  728.  */
  729.     if (hp->bh_page_count != page_count)
  730.     {
  731.         vim_free(hp->bh_data);
  732.         if ((hp->bh_data = alloc(mfp->mf_page_size * page_count)) == NULL)
  733.         {
  734.             vim_free(hp);
  735.             return NULL;
  736.         }
  737.         hp->bh_page_count = page_count;
  738.     }
  739.     return hp;
  740. }
  741.  
  742. /*
  743.  * release as many blocks as possible
  744.  * Used in case of out of memory
  745.  *
  746.  * return TRUE if any memory was released
  747.  */
  748.     int
  749. mf_release_all()
  750. {
  751.     BUF            *buf;
  752.     MEMFILE        *mfp;
  753.     BHDR        *hp;
  754.     int            retval = FALSE;
  755.  
  756.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  757.     {
  758.         mfp = buf->b_ml.ml_mfp;
  759.         if (mfp != NULL && mfp->mf_fd >= 0)        /* only if there is a memfile with a file */
  760.             for (hp = mfp->mf_used_last; hp != NULL; )
  761.             {
  762.                 if (!(hp->bh_flags & BH_LOCKED) &&
  763.                         (!(hp->bh_flags & BH_DIRTY) || mf_write(mfp, hp) != FAIL))
  764.                 {
  765.                     mf_rem_used(mfp, hp);
  766.                     mf_rem_hash(mfp, hp);
  767.                     mf_free_bhdr(hp);
  768.                     hp = mfp->mf_used_last;        /* re-start, list was changed */
  769.                     retval = TRUE;
  770.                 }
  771.                 else
  772.                     hp = hp->bh_prev;
  773.             }
  774.     }
  775.     return retval;
  776. }
  777.  
  778. /*
  779.  * Allocate a block header and a block of memory for it
  780.  */
  781.     static BHDR *
  782. mf_alloc_bhdr(mfp, page_count)
  783.     MEMFILE        *mfp;
  784.     int            page_count;
  785. {
  786.     BHDR    *hp;
  787.  
  788.     if ((hp = (BHDR *)alloc((unsigned)sizeof(BHDR))) != NULL)
  789.     {
  790.         if ((hp->bh_data = (char_u *)alloc(mfp->mf_page_size * page_count))
  791.                                                                       == NULL)
  792.         {
  793.             vim_free(hp);            /* not enough memory */
  794.             return NULL;
  795.         }
  796.         hp->bh_page_count = page_count;
  797.     }
  798.     return hp;
  799. }
  800.  
  801. /*
  802.  * Free a block header and the block of memory for it
  803.  */
  804.     static void
  805. mf_free_bhdr(hp)
  806.     BHDR        *hp;
  807. {
  808.     vim_free(hp->bh_data);
  809.     vim_free(hp);
  810. }
  811.  
  812. /*
  813.  * insert entry *hp in the free list
  814.  */
  815.     static void
  816. mf_ins_free(mfp, hp)
  817.     MEMFILE    *mfp;
  818.     BHDR    *hp;
  819. {
  820.     hp->bh_next = mfp->mf_free_first;
  821.     mfp->mf_free_first = hp;
  822. }
  823.  
  824. /*
  825.  * remove the first entry from the free list and return a pointer to it
  826.  * Note: caller must check that mfp->mf_free_first is not NULL!
  827.  */
  828.     static BHDR *
  829. mf_rem_free(mfp)
  830.     MEMFILE    *mfp;
  831. {
  832.     BHDR    *hp;
  833.  
  834.     hp = mfp->mf_free_first;
  835.     mfp->mf_free_first = hp->bh_next;
  836.     return hp;
  837. }
  838.  
  839. /*
  840.  * read a block from disk
  841.  * 
  842.  * Return FAIL for failure, OK otherwise
  843.  */
  844.     static int
  845. mf_read(mfp, hp)
  846.     MEMFILE        *mfp;
  847.     BHDR        *hp;
  848. {
  849.     long_u        offset;
  850.     unsigned    page_size;
  851.     unsigned    size;
  852.  
  853.     if (mfp->mf_fd < 0)        /* there is no file, can't read */
  854.         return FAIL;
  855.  
  856.     page_size = mfp->mf_page_size;
  857.     offset = page_size * hp->bh_bnum;
  858.     size = page_size * hp->bh_page_count;
  859.     if ((long_u)lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
  860.     {
  861.         EMSG("Seek error in swap file read");
  862.         return FAIL;
  863.     }
  864.     if ((unsigned)read(mfp->mf_fd, (char *)hp->bh_data, (size_t)size) != size)
  865.     {
  866.         EMSG("Read error in swap file");
  867.         return FAIL;
  868.     }
  869.     return OK;
  870. }
  871.  
  872. /*
  873.  * write a block to disk
  874.  * 
  875.  * Return FAIL for failure, OK otherwise
  876.  */
  877.     static int
  878. mf_write(mfp, hp)
  879.     MEMFILE        *mfp;
  880.     BHDR        *hp;
  881. {
  882.     long_u        offset;        /* offset in the file */
  883.     blocknr_t    nr;            /* block nr which is being written */
  884.     BHDR        *hp2;
  885.     unsigned    page_size;    /* number of bytes in a page */
  886.     unsigned    page_count;    /* number of pages written */
  887.     unsigned    size;        /* number of bytes written */
  888.  
  889.     if (mfp->mf_fd < 0)        /* there is no file, can't write */
  890.         return FAIL;
  891.  
  892.     if (hp->bh_bnum < 0)        /* must assign file block number */
  893.         if (mf_trans_add(mfp, hp) == FAIL)
  894.             return FAIL;
  895.  
  896.     page_size = mfp->mf_page_size;
  897.  
  898.     /*
  899.      * We don't want gaps in the file. Write the blocks in front of *hp
  900.      * to extend the file.
  901.      * If block 'mf_infile_count' is not in the hash list, it has been
  902.      * freed. Fill the space in the file with data from the current block.
  903.      */
  904.     for (;;)
  905.     {
  906.         nr = hp->bh_bnum;
  907.         if (nr > mfp->mf_infile_count)            /* beyond end of file */
  908.         {
  909.             nr = mfp->mf_infile_count;
  910.             hp2 = mf_find_hash(mfp, nr);        /* NULL catched below */
  911.         }
  912.         else
  913.             hp2 = hp;
  914.  
  915.         offset = page_size * nr;
  916.         if ((long_u)lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
  917.         {
  918.             EMSG("Seek error in swap file write");
  919.             return FAIL;
  920.         }
  921.         if (hp2 == NULL)            /* freed block, fill with dummy data */
  922.             page_count = 1;
  923.         else
  924.             page_count = hp2->bh_page_count;
  925.         size = page_size * page_count;
  926.         if ((unsigned)write(mfp->mf_fd,
  927.              (char *)(hp2 == NULL ? hp : hp2)->bh_data, (size_t)size) != size)
  928.         {
  929.             /*
  930.              * Avoid repeating the error message, this mostly happens when the
  931.              * disk is full. We give the message again only after a succesful
  932.              * write or when hitting a key. We keep on trying, in case some
  933.              * space becomes available.
  934.              */
  935.             if (!did_swapwrite_msg)
  936.                 EMSG("Write error in swap file");
  937.             did_swapwrite_msg = TRUE;
  938.             return FAIL;
  939.         }
  940.         did_swapwrite_msg = FALSE;
  941.         if (hp2 != NULL)                    /* written a non-dummy block */
  942.             hp2->bh_flags &= ~BH_DIRTY;
  943.                                             /* appended to the file */
  944.         if (nr + (blocknr_t)page_count > mfp->mf_infile_count)
  945.             mfp->mf_infile_count = nr + page_count;
  946.         if (nr == hp->bh_bnum)                /* written the desired block */
  947.             break;
  948.     }
  949.     return OK;
  950. }
  951.  
  952. /*
  953.  * Make block number for *hp positive and add it to the translation list
  954.  * 
  955.  * Return FAIL for failure, OK otherwise
  956.  */
  957.     static int
  958. mf_trans_add(mfp, hp)
  959.     MEMFILE    *mfp;
  960.     BHDR    *hp;
  961. {
  962.     BHDR        *freep;
  963.     blocknr_t    new_bnum;
  964.     int            hash;
  965.     NR_TRANS    *np;
  966.     int            page_count;
  967.  
  968.     if (hp->bh_bnum >= 0)                    /* it's already positive */
  969.         return OK;
  970.  
  971.     if ((np = (NR_TRANS *)alloc((unsigned)sizeof(NR_TRANS))) == NULL)
  972.         return FAIL;
  973.  
  974. /*
  975.  * get a new number for the block.
  976.  * If the first item in the free list has sufficient pages, use its number
  977.  * Otherwise use mf_blocknr_max.
  978.  */
  979.     freep = mfp->mf_free_first;
  980.     page_count = hp->bh_page_count;
  981.     if (freep != NULL && freep->bh_page_count >= page_count)
  982.     {
  983.         new_bnum = freep->bh_bnum;
  984.         /*
  985.          * If the page count of the free block was larger, recude it.
  986.          * If the page count matches, remove the block from the free list
  987.          */
  988.         if (freep->bh_page_count > page_count)
  989.         {
  990.             freep->bh_bnum += page_count;
  991.             freep->bh_page_count -= page_count;
  992.         }
  993.         else
  994.         {
  995.             freep = mf_rem_free(mfp);
  996.             vim_free(freep);
  997.         }
  998.     }
  999.     else
  1000.     {
  1001.         new_bnum = mfp->mf_blocknr_max;
  1002.         mfp->mf_blocknr_max += page_count;
  1003.     }
  1004.  
  1005.     np->nt_old_bnum = hp->bh_bnum;            /* adjust number */
  1006.     np->nt_new_bnum = new_bnum;
  1007.  
  1008.     mf_rem_hash(mfp, hp);                    /* remove from old hash list */
  1009.     hp->bh_bnum = new_bnum;
  1010.     mf_ins_hash(mfp, hp);                    /* insert in new hash list */
  1011.  
  1012.     hash = MEMHASH(np->nt_old_bnum);        /* insert in trans list */
  1013.     np->nt_next = mfp->mf_trans[hash];
  1014.     mfp->mf_trans[hash] = np;
  1015.     if (np->nt_next != NULL)
  1016.         np->nt_next->nt_prev = np;
  1017.     np->nt_prev = NULL;    
  1018.  
  1019.     return OK;
  1020. }
  1021.  
  1022. /*
  1023.  * Lookup a tranlation from the trans lists and delete the entry
  1024.  * 
  1025.  * Return the positive new number when found, the old number when not found
  1026.  */
  1027.      blocknr_t
  1028. mf_trans_del(mfp, old_nr)
  1029.     MEMFILE        *mfp;
  1030.     blocknr_t    old_nr;
  1031. {
  1032.     int            hash;
  1033.     NR_TRANS    *np;
  1034.     blocknr_t    new_bnum;
  1035.  
  1036.     hash = MEMHASH(old_nr);
  1037.     for (np = mfp->mf_trans[hash]; np != NULL; np = np->nt_next)
  1038.         if (np->nt_old_bnum == old_nr)
  1039.             break;
  1040.     if (np == NULL)                /* not found */
  1041.         return old_nr;
  1042.  
  1043.     mfp->mf_neg_count--;
  1044.     new_bnum = np->nt_new_bnum;
  1045.     if (np->nt_prev != NULL)            /* remove entry from the trans list */
  1046.         np->nt_prev->nt_next = np->nt_next;
  1047.     else
  1048.         mfp->mf_trans[hash] = np->nt_next;
  1049.     if (np->nt_next != NULL)
  1050.         np->nt_next->nt_prev = np->nt_prev;
  1051.     vim_free(np);
  1052.  
  1053.     return new_bnum;
  1054. }
  1055.  
  1056. /*
  1057.  * Set mfp->mf_xfname according to mfp->mf_fname and some other things.
  1058.  * Don't get the full path name if did_cd is TRUE, then fname should
  1059.  * already be a full path name.
  1060.  */
  1061.     void
  1062. mf_set_xfname(mfp)
  1063.     MEMFILE        *mfp;
  1064. {
  1065.     mfp->mf_xfname = NULL;
  1066.     if (!did_cd)
  1067.         mfp->mf_xfname = FullName_save(mfp->mf_fname);
  1068. }
  1069.  
  1070. /*
  1071.  * Make the name of the file used for the memfile a full path.
  1072.  * Used before doing a :cd
  1073.  */
  1074.     void
  1075. mf_fullname(mfp)
  1076.     MEMFILE        *mfp;
  1077. {
  1078.     if (mfp != NULL && mfp->mf_fname != NULL && mfp->mf_xfname != NULL)
  1079.     {
  1080.         vim_free(mfp->mf_fname);
  1081.         mfp->mf_fname = mfp->mf_xfname;
  1082.         mfp->mf_xfname = NULL;
  1083.     }
  1084. }
  1085.  
  1086. /*
  1087.  * return TRUE if there are any translations pending for 'mfp'
  1088.  */
  1089.     int
  1090. mf_need_trans(mfp)
  1091.     MEMFILE        *mfp;
  1092. {
  1093.     return (mfp->mf_fname != NULL && mfp->mf_neg_count > 0);
  1094. }
  1095.  
  1096. #if 1            /* included for beta release, TODO: remove later */
  1097. /*
  1098.  * print statistics for a memfile (for debugging)
  1099.  */
  1100.     void
  1101. mf_statistics()
  1102. {
  1103.     MEMFILE        *mfp;
  1104.     BHDR        *hp;
  1105.     int            used = 0;
  1106.     int            locked = 0;
  1107.     int            dirty = 0;
  1108.     int            nfree = 0;
  1109.     int            negative = 0;
  1110.  
  1111.     mfp = curbuf->b_ml.ml_mfp;
  1112.     if (mfp == NULL)
  1113.         MSG("No memfile");
  1114.     else
  1115.     {
  1116.         for (hp = mfp->mf_used_first; hp != NULL; hp = hp->bh_next)
  1117.         {
  1118.             ++used;
  1119.             if (hp->bh_flags & BH_LOCKED)
  1120.                 ++locked;
  1121.             if (hp->bh_flags & BH_DIRTY)
  1122.                 ++dirty;
  1123.             if (hp->bh_bnum < 0)
  1124.                 ++negative;
  1125.         }
  1126.         for (hp = mfp->mf_free_first; hp != NULL; hp = hp->bh_next)
  1127.             ++nfree;
  1128.         sprintf((char *)IObuff, "%d used (%d locked, %d dirty, %d (%d) negative), %d free",
  1129.                         used, locked, dirty, negative, (int)mfp->mf_neg_count, nfree);
  1130.         msg(IObuff);
  1131.         sprintf((char *)IObuff, "Total mem used is %ld bytes", total_mem_used);
  1132.         msg(IObuff);
  1133.     }
  1134. }
  1135. #endif
  1136.  
  1137. /*
  1138.  * open a swap file for a memfile
  1139.  */
  1140.     static void
  1141. mf_do_open(mfp, fname, trunc_file)
  1142.     MEMFILE        *mfp;
  1143.     char_u        *fname;
  1144.     int            trunc_file;
  1145. {
  1146.     mfp->mf_fname = fname;
  1147.     /*
  1148.      * Get the full path name before the open, because this is
  1149.      * not possible after the open on the Amiga.
  1150.      * fname cannot be NameBuff, because it must have been allocated.
  1151.      */
  1152.     mf_set_xfname(mfp);
  1153.  
  1154.     /*
  1155.      * try to open the file
  1156.      */
  1157.     mfp->mf_fd = open((char *)fname,
  1158.             (trunc_file ? (O_CREAT | O_RDWR | O_TRUNC) : (O_RDONLY)) | O_EXTRA
  1159.  
  1160. #ifdef AMIGA                /* Amiga has no mode argument */
  1161.                     );
  1162. #endif
  1163. #ifdef UNIX                    /* open in rw------- mode */
  1164.                     , (mode_t)0600);
  1165. #endif
  1166. #if defined(MSDOS) || defined(WIN32) || defined(__EMX__)
  1167.                     , S_IREAD | S_IWRITE);         /* open read/write */
  1168. #endif
  1169. #ifdef VMS                    /* open in rw------- mode */
  1170.                     , 0600);
  1171. #endif
  1172.  
  1173.     /*
  1174.      * If the file cannot be opened, use memory only
  1175.      */
  1176.     if (mfp->mf_fd < 0)
  1177.     {
  1178.         vim_free(mfp->mf_xfname);
  1179.         mfp->mf_fname = NULL;
  1180.         mfp->mf_xfname = NULL;
  1181.     }
  1182. }
  1183.